/**
 * Copyright (c) 2015-2030 by Beijing Yanlight Co., Ltd.
 * All rights reserved.
 */
package com.yanlight.app.service.impl;

import com.yanlight.util.LogUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yanlight.app.request.AlipayProviderSignGrantRequest;
import com.yanlight.app.request.OrderPlaceRequest;
import com.yanlight.app.response.OrderPlaceResponse;
import com.yanlight.app.service.AlipayService;
import com.yanlight.exception.ErrorType;
import com.yanlight.exception.TradeException;
import com.yanlight.support.alipay.AlipayConstants;
import com.yanlight.support.alipay.AlipayFactory;
import com.yanlight.type.StatusType;
import com.yanlight.app.response.AlipayProviderSignGrantResponse;
import com.yanlight.app.response.OrderAlipayPlaceResponse;
import com.yanlight.app.dal.entity.AlipayConfig;
import com.yanlight.util.DateTimeUtil;
import com.yanlight.util.JedisUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayOpenAuthTokenAppModel;
import com.alipay.api.domain.AlipayTradeCreateModel;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.request.AlipayOpenAuthTokenAppRequest;
import com.alipay.api.request.AlipayTradeCreateRequest;
import com.alipay.api.response.AlipayOpenAuthTokenAppResponse;
import com.alipay.api.response.AlipayTradeCreateResponse;
import com.yanlight.app.dal.dao.AlipayConfigDAO;

/**
 * 
 * @author haolw
 * @time 2017/12/07
 */
@Service
public class AlipayServiceImpl implements AlipayService {
	private final String ALIPAY_CONFIG_KEY_PREFIX = "trade_alipay_config_";
	@Autowired
	private AlipayConfigDAO alipayConfigDAO;

	public AlipayConfig findConfig(Integer companyId) {
		AlipayConfig config = null;
		String key = getAlipayConfigKey(companyId);
		Boolean exists = JedisUtil.exists(key);
		if (!exists) {
			config = alipayConfigDAO.findByCompanyId(companyId);
			if (config != null) {
				JedisUtil.set(key, config);
			}
		} else {
			config = JedisUtil.get(key, AlipayConfig.class);
		}
		verifyAuthToken(key, config);
		return config;
	}

	@Override
	public boolean checkConfig(Integer companyId) {
		AlipayConfig config = findConfig(companyId);
		if (config == null) {
			return false;
		}
		if (config.getStatus().equals(StatusType.UNACTIVITY.ordinal())) {
			return false;
		}
		if (StringUtils.isEmpty(config.getMchUserId()) || StringUtils.isEmpty(config.getAuthToken())) {
			return false;
		}
		return true;
	}

	@Override
	public boolean validate(OrderPlaceRequest request) {
		Integer companyId = request.getCompanyId();
		String buyerId = request.getBuyerId();
		String fromFee = request.getTotalFee();
		if (companyId == null) {
			throw TradeException.error(ErrorType.NO_OPEN_SERVICE);
		}
		if (StringUtils.isBlank(buyerId) || StringUtils.isBlank(fromFee)) {
			throw TradeException.error(ErrorType.INCOMPLETE_PARAMETERS);
		}
		AlipayConfig config = findConfig(companyId);
		if (config == null) {
			throw TradeException.error(ErrorType.NO_OPEN_SERVICE);
		}
		String mchUserId = config.getMchUserId();
		String authToken = config.getAuthToken();
		if (StringUtils.isBlank(mchUserId) || StringUtils.isBlank(authToken)) {
			throw TradeException.error(ErrorType.NO_OPEN_SERVICE);
		}
		return true;
	}

	@Override
	public String getMchUserId(Integer companyId) {
		AlipayConfig alipayConfig = findConfig(companyId);
		if (alipayConfig == null) {
			return null;
		}
		return alipayConfig.getMchUserId();
	}

	@Override
	public OrderPlaceResponse placeOrder(OrderPlaceRequest request) {
		Integer companyId = request.getCompanyId();
		AlipayConfig alipayConfig = findConfig(companyId);
		String sellerId = alipayConfig.getMchUserId();
		String authToken = alipayConfig.getAuthToken();
		String notifyUrl = AlipayConstants.getNotifyUrl(companyId);
		String outTradeNo = request.getOutTradeNo();
		String buyerId = request.getBuyerId();
		String fromFee = request.getTotalFee();
		String sn = request.getSn();
		String companyShortName = request.getCompanyShortName();
		String body = AlipayConstants.getBody(companyShortName, sn);

		AlipayClient alipayClient = AlipayFactory.providerClient();
		AlipayTradeCreateRequest tradeRequest = new AlipayTradeCreateRequest();
		AlipayTradeCreateModel model = new AlipayTradeCreateModel();
		ExtendParams extendParams = new ExtendParams();
		model.setOutTradeNo(outTradeNo);
		model.setSellerId(sellerId);
		model.setTotalAmount(NumberUtils.createDouble(fromFee).toString());
		model.setBuyerId(buyerId);
		model.setSubject(companyShortName);
		model.setTimeoutExpress(AlipayConstants.timeoutExpress);
		model.setBody(body);
		extendParams.setSysServiceProviderId(AlipayConstants.partnerId);
		model.setExtendParams(extendParams);
		tradeRequest.setBizModel(model);
		tradeRequest.setNotifyUrl(notifyUrl);
		tradeRequest.putOtherTextParam("app_auth_token", authToken);
		AlipayTradeCreateResponse tradeResponse;
		OrderAlipayPlaceResponse response = new OrderAlipayPlaceResponse();
		try {
			tradeResponse = alipayClient.execute(tradeRequest);
			LogUtil.showLog("支付宝下单",tradeResponse);
			if (tradeResponse.isSuccess()) {
				response.setTradeNO(tradeResponse.getTradeNo());
			} else {
				throw TradeException.error(ErrorType.PLACE_ORDER_FAILURE);
			}
		} catch (AlipayApiException e) {
			e.printStackTrace();
			throw TradeException.error(ErrorType.PLACE_ORDER_FAILURE);
		}

		return response;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public AlipayProviderSignGrantResponse signGrant(AlipayProviderSignGrantRequest request) {
		AlipayProviderSignGrantResponse response = new AlipayProviderSignGrantResponse();
		Integer companyId = request.getCid();
		String pid = request.getPid();
		AlipayConfig config = alipayConfigDAO.findByCompanyIdAndPid(companyId, pid);
		if (config == null) {
			response.noConfigError();
			return response;
		}
		String appAuthCode = request.getAppAuthCode();
		AlipayClient alipayClient = AlipayFactory.providerClient();
		AlipayOpenAuthTokenAppRequest alipayRequest = new AlipayOpenAuthTokenAppRequest();
		AlipayOpenAuthTokenAppModel alipayModel = new AlipayOpenAuthTokenAppModel();
		alipayModel.setGrantType(AlipayConstants.AUTH_GRANTTYPE_CODE);
		alipayModel.setCode(appAuthCode);
		alipayRequest.setBizModel(alipayModel);
		try {
			AlipayOpenAuthTokenAppResponse alipayResponse = alipayClient.execute(alipayRequest);
			if (alipayResponse.isSuccess()) {
				String mchUserId = alipayResponse.getUserId();
				String authToken = alipayResponse.getAppAuthToken();
				String refreshToken = alipayResponse.getAppRefreshToken();
				Integer expiresIn = Integer.valueOf(alipayResponse.getExpiresIn());
				if (pid.equals(mchUserId)) {
					config.setAuthToken(authToken);
					config.setStatus(StatusType.ACTIVITY.ordinal());
					config.setRefreshToken(refreshToken);
					config.setCreateTime(DateTimeUtil.getNowTime());
					config.setExpireTime(DateTimeUtil.plusSecond(expiresIn - 60));
					alipayConfigDAO.update(config);
					String key = getAlipayConfigKey(companyId);
					JedisUtil.set(key, config);
				} else {
					response.authNotmatch();
				}
			} else {
				response.authError();
			}
		} catch (Exception e) {
			e.printStackTrace();
			response.authError();
		}
		return response;
	}

	private void verifyAuthToken(String key, AlipayConfig config) {
		if (config == null) {
			return;
		}
		if (StringUtils.isBlank(config.getAuthToken())) {
			return;
		}
		if (StringUtils.isBlank(config.getRefreshToken())) {
			return;
		}
		if (StringUtils.isBlank(config.getExpireTime())) {
			return;
		}
		String expiresTime = config.getExpireTime();
		boolean expire = DateTimeUtil.checkExpire(expiresTime);
		if (expire) {
			try {
				AlipayClient alipayClient = AlipayFactory.providerClient();
				AlipayOpenAuthTokenAppRequest authRequest = new AlipayOpenAuthTokenAppRequest();
				AlipayOpenAuthTokenAppModel authModel = new AlipayOpenAuthTokenAppModel();
				authModel.setRefreshToken(config.getRefreshToken());
				authModel.setGrantType(AlipayConstants.AUTH_GRANTTYPE_REFRESH);
				authRequest.setBizModel(authModel);
				AlipayOpenAuthTokenAppResponse tokenResponse = alipayClient.execute(authRequest);
				if (tokenResponse.isSuccess()) {
					String appAuthToken = tokenResponse.getAppAuthToken();
					String appRefreshToken = tokenResponse.getAppRefreshToken();
					String expiresIn = tokenResponse.getExpiresIn();
					Integer expiresSeconds = Integer.valueOf(expiresIn) - 10 * 60;
					config.setAuthToken(appAuthToken);
					config.setRefreshToken(appRefreshToken);
					config.setExpireTime(DateTimeUtil.plusSecond(expiresSeconds));
					alipayConfigDAO.update(config);
					JedisUtil.set(key, config);
				} else {
					throw new AlipayApiException(tokenResponse.getSubMsg());
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}

	private String getAlipayConfigKey(Integer companyId) {
		return ALIPAY_CONFIG_KEY_PREFIX + companyId;
	}

}